#include <csignal>
#include <iostream>
#include <unistd.h>

#include "core/ipc/IPCManager.h"
#include "core/ipc/Message.h"
#include "core/plugin/PluginManager.h"
#include "core/plugin/TimerPlugin.h"
#include "utils/Log.h"

struct Demo1 {
    struct RS485Receiver final : MessageReceiver {
        void onReceived(const std::shared_ptr<Message> &intent) override {
            Log::d("RS485Receiver", "onReceived() : '" + intent->toString() + "'");
        }
    };

    static IPCManager ipcManager;
    static const std::shared_ptr<RS485Receiver> receiver;
    static const std::shared_ptr<Topic> topic;
    static const std::shared_ptr<Message> msg;

    static void signalHandler(const int signal) {
        if (signal == SIGTERM) {
            Log::i("MAIN", "Caught SIGINT: Terminating program.");
            ipcManager.unsubscribe(topic, receiver);
            ipcManager.stop();

            std::exit(0);
        }
    }

    static int main() {
        std::signal(SIGTERM, signalHandler);
        Log::i("MAIN", "Program is running. Press Ctrl+C to interrupt.");

        msg->putInt("temperature", 123);
        msg->putString("timestamp", "22:06:13.325");

        ipcManager.start();
        ipcManager.subscribe(topic, receiver);
        ipcManager.publishMessage(msg);
        ipcManager.publishMessage(msg);
        ipcManager.loopForever();

        return 0;
    }
};

const auto receiver = std::make_shared<Demo1::RS485Receiver>();
const auto topic = std::make_shared<Topic>("/Southern/Bus/rs485/frame");
const auto msg = std::make_shared<Message>("/Southern/Bus/rs485/frame");

struct Demo2 {
    static void signalHandler(const int signal) {
        if (signal == SIGTERM) {
            Log::i("MAIN", "Caught SIGINT: Terminating program.");
            PluginManager::instance().dispose();
            std::exit(0);
        }
    }

    static int main() {
        Log::NOISE();

        std::signal(SIGTERM, signalHandler);
        Log::i("MAIN", "Program is running. Press Ctrl+C to interrupt.");

        PluginManager::instance().initialize();
        PluginManager::instance().loopForever();
        return 0;
    }
};

int main() {
    // Demo1::main();
    Demo2::main();
}
